﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Speech.Synthesis;
using System.Threading;
using System.Xml;
using Ellanet.Classes;
using Ellanet.Properties;
using Ellanet.Utilities;

namespace Ellanet.ViewModels
{
    public class SelectionWindowViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public event RequestViewCloseHandler RequestViewClose;

        private List<Multiplicand> _multiplicands;
        private List<VoiceRate> _voiceRates;
        private List<VoiceName> _voiceNames;
        private int _intervalSeconds = 5;
        private bool _updateAvailable;
        private bool _randomise = true;

        public delegate void RequestViewCloseHandler();

        public RelayCommand PractiseCommand { get; set; }

        public RelayCommand TestCommand { get; set; }

        public int VoiceRate { get; set; }

        public StaticCode.Activity Activity { get; set; }

        public List<Sum> Sums { get; set; }

        public List<Multiplicand> Multiplicands
        {
            get { return _multiplicands ?? (_multiplicands = (from int i in Enumerable.Range(2, 11) select new Multiplicand { Value = i }).ToList()); }
            set
            {
                _multiplicands = value;
                OnPropertyChanged();
            }
        }

        public List<VoiceRate> VoiceRates
        {
            get
            {
                return _voiceRates ?? (_voiceRates = new List<VoiceRate>
                {
                    new VoiceRate {Name = "Slow", Rate = -8},
                    new VoiceRate {Name = "Slower", Rate = -4},
                    new VoiceRate {Name = "Normal", Rate = 0, IsSelected = true},
                    new VoiceRate {Name = "Faster", Rate = 4},
                    new VoiceRate {Name = "Fast", Rate = 8}
                });
            }
            set
            {
                _voiceRates = value;
                OnPropertyChanged();
            }
        }

        public List<VoiceName> VoiceNames
        {
            get { return _voiceNames ?? (_voiceNames = (from InstalledVoice voice in (new SpeechSynthesizer()).GetInstalledVoices() select new VoiceName { Name = voice.VoiceInfo.Name, IsSelected = voice.VoiceInfo.Culture.Equals(CultureInfo.CurrentCulture) }).ToList()); }
            set
            {
                _voiceNames = value;
                OnPropertyChanged();
            }
        }

        public int IntervalSeconds
        {
            get { return _intervalSeconds; }
            set
            {
                _intervalSeconds = value;
                OnPropertyChanged();
            }
        }

        public bool UpdateAvailable
        {
            get { return _updateAvailable; }
            set
            {
                _updateAvailable = value;
                OnPropertyChanged();
            }
        }

        public bool Randomise
        {
            get { return _randomise; }
            set
            {
                _randomise = value;
                OnPropertyChanged();
            }
        }

        public SelectionWindowViewModel()
        {
            PractiseCommand = new RelayCommand(param => ProceedToActivity(StaticCode.Activity.Practise), param => CanProceedToActivity());
            TestCommand = new RelayCommand(param => ProceedToActivity(StaticCode.Activity.Test), param => CanProceedToActivity());
            Activity = StaticCode.Activity.None;
            ThreadPool.QueueUserWorkItem(CheckForUpdate);
        }

        private void CheckForUpdate(object stateInfo)
        {
            try
            {
                var versionXmlDoc = new XmlDocument();
                versionXmlDoc.Load(StaticCode.VersionXmlUrl);

                if (versionXmlDoc.DocumentElement != null)
                {
                    var availableVersion = new Version(versionXmlDoc.DocumentElement.InnerText);

                    if (availableVersion > Assembly.GetExecutingAssembly().GetName().Version)
                    {
                        UpdateAvailable = true;
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }

        private void ProceedToActivity(StaticCode.Activity activity)
        {
            Sums = GetSums();

            foreach (var sum in Sums)
            {
                Debug.WriteLine("{0} x {1}", sum.Multiplicand, sum.Multiplier);
            }

            OnRequestViewClose(activity);
        }

        private bool CanProceedToActivity()
        {
            return Multiplicands.Any(multiplicand => multiplicand.IsSelected);
        }

        private List<Sum> GetSums()
        {
            var multiplicands = (from Multiplicand multiplicand in Multiplicands where multiplicand.IsSelected select multiplicand.Value).ToList();
            var sums = (from int i in Enumerable.Range(1, 12) select new Sum { Multiplier = multiplicands.OrderBy(multiplicand => Guid.NewGuid()).First(), Multiplicand = i }).ToList();
            return _randomise ? sums.OrderBy(sum => Guid.NewGuid()).ToList() : sums;
        }

        protected void OnRequestViewClose(StaticCode.Activity activity)
        {
            Activity = activity;
            RequestViewClose?.Invoke();
        }

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
